package com.un.ebs.sys.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.sys.domain.AppTenantExt;
import com.un.ebs.sys.domain.Ent;
import com.un.ebs.sys.domain.UserExt;
import com.un.ebs.sys.service.*;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liubo
 * @email liubocs@163.com
 * @date 2020/3/5 22:57
 */
@Service
public class WxServiceImpl implements WxService {

//    @Autowired
//    private WxMpService wxMpService;

    @Autowired
    private EntService entService;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisService redisService;

    @Resource
    private AppTenantService appTenantService;

    private final Logger logger = LoggerFactory.getLogger(WxServiceImpl.class);

    @Override
    public void sendTemplateMessage(String tenantId, String title, String userId, String templateId, Map<String, String> data, String url) {
        AppTenantExt tenant = appTenantService.queryViewById(tenantId);
        if (tenant == null) {
            logger.warn("租户ID不能为空。");
            return;
        }

        if (StringUtils.isNullOrEmpty(templateId)) {
            logger.warn(String.format("当前租户没有配置%s模板ID。", title));
            return;
        }
        if (data == null) {
            logger.warn(String.format("当前租户没有配置%s模板的参数。", title));
            return;
        }

        if (StringUtils.isNullOrEmpty(userId)) {
            logger.warn(String.format("当前用户ID为空。"));
            return;
        }
        UserExt u = userService.getUserExt(userId);
        if (u == null) {
            logger.warn(String.format("当前用户【%s】无效。", userId));
        }

        String openId = userService.getOpenId(userId, tenantId);
        if (StringUtils.isNullOrEmpty(openId)) {
            openId = userService.getOpenIdByEnt(userId, tenant.getEntId());
            if (StringUtils.isNullOrEmpty(openId)) {
                if (tenant == null) {
                    logger.warn(String.format("用户【%s - %s】没有在租户【%s】中做微信绑定。", u.getUserName(), u.getPersonnelName(), tenantId));
                } else {
                    logger.warn(String.format("用户【%s - %s】没有在租户【%s】中做微信绑定。", u.getUserName(), u.getPersonnelName(), tenant.getTenantName()));
                }
                return;
            }
        }

        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(openId)
                .templateId(templateId)
                .url(url)
                .build();

        for (String key : data.keySet()) {
            if (StringUtils.isNullOrEmpty(data.get(key))) {
                continue;
            }
            templateMessage.addData(new WxMpTemplateData(key, data.get(key)));
        }

        try {
            Ent ent = entService.queryByTenantId(tenantId);
            templateMessage.getData().forEach(s -> System.out.println(String.format("%s : %s", s.getName(), s.getValue())));
            getWxMpService().switchoverTo(ent.getWxAppId()).getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
            logger.error(String.format("发送%s时出错：%s", title, e.getMessage()));
            e.printStackTrace();
        }
    }

    @Override
    public void sendTemplateMessage(String tenantId, String userId, String templateId, String first, String keyword1, String keyword2, String keyword3, String keyword4, String remark, String url) {
        Ent ent = entService.queryByTenantId(tenantId);
        if (StringUtils.isNullOrEmpty(templateId)) {
            logger.warn(String.format("当前租户没有配置%s模板ID。", first));
            return;
        }

        if (StringUtils.isNullOrEmpty(userId)) {
            logger.warn(String.format("当前用户ID为空。"));
            return;
        }
        UserExt u = userService.getUserExt(userId);
        if (u == null) {
            logger.warn(String.format("当前用户【%s】无效。", userId));
            return;
        }
        String openId = userService.getOpenId(userId, tenantId);
        if (StringUtils.isNullOrEmpty(openId)) {
            logger.warn(String.format("当前用户【%s - %s】没有绑定微信。", u.getUserName(), u.getPersonnelName()));
            return;
        }
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(openId)
                .templateId(templateId)
                .url(url)
                .build();

        if (!StringUtils.isNullOrEmpty(first)) {
            templateMessage.addData(new WxMpTemplateData("first", first));
        }
        if (!StringUtils.isNullOrEmpty(keyword1)) {
            templateMessage.addData(new WxMpTemplateData("keyword1", keyword1));
        }
        if (!StringUtils.isNullOrEmpty(keyword2)) {
            templateMessage.addData(new WxMpTemplateData("keyword2", keyword2));
        }
        if (!StringUtils.isNullOrEmpty(keyword3)) {
            templateMessage.addData(new WxMpTemplateData("keyword3", keyword3));
        }
        if (!StringUtils.isNullOrEmpty(keyword4)) {
            templateMessage.addData(new WxMpTemplateData("keyword4", keyword4));
        }
        if (!StringUtils.isNullOrEmpty(remark)) {
            templateMessage.addData(new WxMpTemplateData("remark", remark));
        }

        try {
            templateMessage.getData().forEach(s -> System.out.println(String.format("%s : %s", s.getName(), s.getValue())));
            getWxMpService().switchoverTo(ent.getWxAppId()).getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
            logger.error(String.format("发送%s时出错：%s", first, e.getMessage()));
            e.printStackTrace();
        }
    }

    @Override
    public void sendMessage(String tenantId, String userId, String templateId, String first, String userData, String reasonData, String addressData, String remark) {
        Ent ent = entService.queryByTenantId(tenantId);
        if (StringUtils.isNullOrEmpty(templateId)) {
            logger.warn(String.format("当前租户没有配置%s模板ID。", first));
            return;
        }

        if (StringUtils.isNullOrEmpty(userId)) {
            logger.warn(String.format("当前用户ID为空。"));
            return;
        }
        UserExt u = userService.getUserExt(userId);
        if (u == null) {
            logger.warn(String.format("当前用户【%s】无效。", userId));
            return;
        }
        String openId = userService.getOpenId(userId, tenantId);
        if (StringUtils.isNullOrEmpty(openId)) {
            logger.warn(String.format("当前用户【%s - %s】没有绑定微信。", u.getUserName(), u.getPersonnelName()));
            return;
        }
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(openId)
                .templateId(templateId)
                .url(null)
                .build();

        if (!StringUtils.isNullOrEmpty(first)) {
            templateMessage.addData(new WxMpTemplateData("first", first, "red"));
        }
        if (!StringUtils.isNullOrEmpty(userData)) {
            templateMessage.addData(new WxMpTemplateData("user", userData));
        }
        if (!StringUtils.isNullOrEmpty(reasonData)) {
            templateMessage.addData(new WxMpTemplateData("reason", reasonData));
        }
        if (!StringUtils.isNullOrEmpty(addressData)) {
            templateMessage.addData(new WxMpTemplateData("address", addressData));
        }
        if (!StringUtils.isNullOrEmpty(remark)) {
            templateMessage.addData(new WxMpTemplateData("remark", remark));
        }

        try {
            templateMessage.getData().forEach(s -> System.out.println(String.format("%s : %s", s.getName(), s.getValue())));
            getWxMpService().switchoverTo(ent.getWxAppId()).getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
            logger.error(String.format("发送%s时出错：%s", first, e.getMessage()));
            e.printStackTrace();
        }
    }

    @Override
    public WxPayService getWxPayService(String tenantId) {
        Ent ent = entService.queryByTenantId(tenantId);
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(org.apache.commons.lang3.StringUtils.trimToNull(ent.getWxAppId()));
        payConfig.setMchId(org.apache.commons.lang3.StringUtils.trimToNull(ent.getWxMachId()));
        payConfig.setMchKey(org.apache.commons.lang3.StringUtils.trimToNull(ent.getWxMachKey()));
        payConfig.setKeyPath(ent.getWxKeyPath());

        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);

        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }

    @Override
    public WxCpService getWxCpService() {
        return getWxCpService(SecurityUtils.getUserContent().getTenantId());
    }

    @Override
    public WxCpService getWxCpService(String tenantId) {
        return getWxCpServiceByEnt(entService.queryByTenantId(tenantId).getId());
    }

    @Override
    public WxCpService getWxCpService(String tenantId, String entId) {
        return getWxCpServiceByEnt(entId);
    }

    private WxCpService getWxCpServiceByEnt(String entId) {
        Ent ent = entService.queryById(entId);
        if (ent == null) {
            throw new BusinessEntityNotFoundException(entId, "企业信息");
        }
        WxCpService service = new WxCpServiceImpl();
        WxCpDefaultConfigImpl storage = new WxCpDefaultConfigImpl();
        storage.setAgentId(Integer.valueOf(ent.getWxCpAgentId()));
        storage.setCorpId(ent.getWxCpCorpId());
        storage.setCorpSecret(ent.getWxCpCorpSecret());
        storage.setAccessToken(ent.getWxCpToken());
        storage.setAesKey(ent.getWxCpAseKey());
        service.setWxCpConfigStorage(storage);
        return service;
    }

    @Override
    public WxMaService getWxMaService() {
        return getWxMaServiceByEnt(SecurityUtils.getUserContent().getEntId());
    }

    @Override
    public WxMaService getWxMaService(String tenantId) {
        return getWxMaServiceByEnt(entService.queryByTenantId(tenantId).getId());
    }

    @Override
    public WxMaService getWxMaService(String tenantId, String entId) {
        return getWxMaServiceByEnt(entId);
    }

    private WxMaService getWxMaServiceByEnt(String entId) {
        Ent ent = entService.queryById(entId);
        if (ent == null) {
            throw new BusinessEntityNotFoundException(entId, "企业信息");
        }

        WxMaService wxMaService = new WxMaServiceImpl();
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(ent.getWxMaAppId());
        config.setSecret(ent.getWxMaSecret());
        config.setAccessToken(ent.getWxMaToken());
        config.setAesKey(ent.getWxMaAseKey());
        config.setMsgDataFormat("JSON");
        wxMaService.setWxMaConfig(config);

        return wxMaService;
    }


    @Override
    public WxMpService getWxMpService(String tenantId) {
        Ent ent = entService.queryByTenantId(tenantId);
        if (ent == null) {
            LoggerFactory.getLogger(WxServiceImpl.class).error("获取WxMpService时，指定了无效的租户ID  [" + tenantId + "]");
            throw new BusinessException("获取WxMpService时，指定了无效的租户ID  [" + tenantId + "]");
        }
        return getWxMpService().switchoverTo(ent.getWxAppId());
        //return wxMpService.switchoverTo(ent.getWxAppId());
    }

    @Override
    public WxMpService getWxMpService(String tenantId, String entId) {
        Ent ent = entService.queryById(entId);
        if (ent == null) {
            ent = entService.queryByTenantId(tenantId);
        }

        if (ent == null) {
            LoggerFactory.getLogger(WxServiceImpl.class).error("获取WxMpService时，指定了无效的租户ID  [" + tenantId + "]");
            throw new BusinessException("获取WxMpService时，指定了无效的租户ID  [" + tenantId + "]");
        }

        return getWxMpService().switchoverTo(ent.getWxAppId());
        //return wxMpService.switchoverTo(ent.getWxAppId());
    }

    @Override
    public String getOpenId(String entId, String tenantId, String code) {
        WxMpUser user = getUserInfo(entId, tenantId, code);
        if (user == null) {
            return null;
        }
        return user.getOpenId();
    }

    @Override
    public WxMpUser getUserInfo(String entId, String tenantId, String code) {
        WxMpUser user;
        try {
            WxMpService wxMpService = getWxMpService(tenantId, entId);


            //WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
            user = convert(wxMpService.getOAuth2Service().getUserInfo(wxMpService.getOAuth2Service().getAccessToken(code), "zh_CN"));
            //user = wxMpService.oauth2getUserInfo(accessToken, "zh_CN");

            // 写缓存
            redisService.set(user.getOpenId(), user, (long) (60 * 60));
            System.out.println();
            System.out.println(DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
            System.out.println("-----------------------------------");
            System.out.println((WxMpUser) redisService.get(user.getOpenId()));
            return user;

        } catch (WxErrorException e) {
            logger.error("获取OpenID失败：" + e.getError().getErrorCode() + " - " + e.getError().getErrorMsg());
            throw new BusinessException("获取OpenID失败：" + e.getError().getErrorCode() + " - " + e.getError().getErrorMsg());
        }
    }

    private WxMpUser convert(WxOAuth2UserInfo user) {
        WxMpUser ret = new WxMpUser();
        ret.setNickname(user.getNickname());
        ret.setOpenId(user.getOpenid());
        ret.setHeadImgUrl(user.getHeadImgUrl());
        ret.setUnionId(user.getUnionId());
        return ret;
    }

    @Bean
    @Override
    public WxMpService getWxMpService() {
        WxMpService service = new WxMpServiceImpl();
        service.setMultiConfigStorages(entService.queryEntWxConfig().stream().map(s -> {
            WxMpDefaultConfigImpl configStore = new WxMpDefaultConfigImpl();
            configStore.setAppId(s.getWxAppId());
            configStore.setSecret(s.getWxAppSecret());
            configStore.setToken(s.getWxToken());
            return configStore;
        }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
        return service;
    }
//    @Override
//    public WxMpService getMpService() {
//        WxMpService service = new WxMpServiceImpl();
//        service.setMultiConfigStorages(entService.queryEntWxConfig().stream().map(s -> {
//            WxMpDefaultConfigImpl configStore = new WxMpDefaultConfigImpl();
//            configStore.setAppId(s.getWxAppId());
//            configStore.setSecret(s.getWxAppSecret());
//            configStore.setToken(s.getWxToken());
//            return configStore;
//        }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
//        return service;
//    }


}
